#ifndef __LOCAL_CACHE_HPP__
#define __LOCAL_CACHE_HPP__

#include <map>
#include <string>
#include <uuid/uuid.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

class local_cache
{
public:
	local_cache(const string& path, int max_size)
		: cache_path_(path), max_size_(max_size)
	{
		pthread_mutex_init(&mutex_, NULL);
	};
	~local_cache()
	{
		pthread_mutex_destroy(&mutex_);
	};
	int create_tmp_file(const string& file, string& tmp_name, mode_t mode = 0644)
	{
		int ret = 0;

		pthread_mutex_lock(&mutex_);
		if(file_map_.find(file) == file_map_.end() ) {
			get_unix_uuid(tmp_name);
			
			int fd = open(tmp_name.c_str(), O_WRONLY|O_CREAT|O_EXCL, mode);
			if(fd <= 0) {
				ret = -1;
			} else {
				ref_cnts_[file] = 1;
				file_map_[file] = tmp_name;
				ret = 0;
			}
			close(fd);
		} else {
			tmp_name =  file_map_[file];
			ref_cnts_[file] += 1;
			ret = ref_cnts_[file] - 1;
		}
		pthread_mutex_unlock(&mutex_);
		return ret;
	};
	int release_tmp_file(const string& file)
	{
		int ret = 0;

		pthread_mutex_lock(&mutex_);
		if(file_map_.find(file) != file_map_.end() ) {
			ref_cnts_[file] -= 1;
			if(ref_cnts_[file] == 0) {
				int c = unlink(file_map_[file].c_str() );
				if(c < 0) {
					ret = -1;
				} else {
					file_map_.erase(file);
					ref_cnts_.erase(file);
					ret = 0;
				}
			} else {
				ret = ref_cnts_[file];
			}
		}
		pthread_mutex_unlock(&mutex_);
		return ret;
	};
	int release_tmp_file(){ return 0;};
	int check_tmp_dir()
	{
		int res = 0;
		long long total = 0;
		pthread_mutex_lock(&mutex_);
		map<string, string>::iterator it;
		for(it = file_map_.begin(); it != file_map_.end(); ++it) {
			struct stat st;
			res = stat(it->second.c_str(), &st);
			if(res == 0) {
				total += st.st_size;
			}
		}
		pthread_mutex_unlock(&mutex_);
		return res;
	};
	int dump_file_map(){ return 0;};
	string tmp_path(const string& file)
	{
		pthread_mutex_lock(&mutex_);
		string ret;
		if(file_map_.find(file) != file_map_.end() ) {
			ret = file_map_[file];
		}
		pthread_mutex_unlock(&mutex_);
		return ret;
	};
private:
	void get_unix_uuid(string& uuid)
	{
		uuid_t uu;
		char out[64];
		uuid_generate_random(uu);
		uuid_unparse(uu, out);
		uuid = string("surtmp") + string(out);
		string::iterator it;
		for (it =uuid.begin(); it != uuid.end(); ++it) {
			if ( *it == '-') {
				uuid.erase(it);
			}
		}
		uuid = cache_path_ + uuid;
		return;
	};
private:
	string cache_path_; // care the /
	int max_size_;
	map<string, string> file_map_;
	map<string, int> ref_cnts_;
	pthread_mutex_t mutex_;
};

#endif